package source.Objetos 
{
    import flash.geom.Point;
    import net.flashpunk.graphics.Spritemap;
    import net.flashpunk.Sfx;
    import net.flashpunk.utils.Input;
    import net.flashpunk.tweens.motion.LinearMotion;
    import source.Assets;
    import source.Global;
	
	public class Enemigo extends Physics {
        //assets:
		public var sprite:Spritemap;
		
		//how fast we accelerate
		public var movement:Number = 0.8;  //ojo con esto, no sé qué es
		public var jump:Number = 12;       //ojo con esto, no sé qué es
        
		//poderes básicos:
		public var caminar:Boolean = true;
		public var salto:Boolean = true;
		public var interactuar:Boolean = true;
		public var agacharse:Boolean = true;
		
		//propiedades "simples":
		public var muerteAlContacto:Boolean = false;
		public var velocidad:Number = 0;
		public var copiasaltos:Boolean = false;
		public var flotante:Boolean = false;
        
        //propiedades "compuestas" (son clases, se encuentran al final de este fichero, bajo el package):
        public var dDireccional:Array; //array de objetos de la clase DisparoDireccional
		
		//movimiento:
        public var movimiento:LinearMotion = new LinearMotion();
        public var listaNodos:Array = new Array();
        public var nodoActual:uint = 0;
        public var direccionMovimiento:Boolean;     //true = hacia la izquierda, false = hacia la derecha
        public var posAnterior:Point = new Point(); //la posición previa a la actual
        
        //otros:
		public var direction:Boolean = true;                     //current player direction (true = right, false = left)
		public var onground:Boolean = false;                     //are we on the ground?
		public var moverDcha:Boolean = false;                    //true si se debe moverse a la derecha (como si fuera la tecla de moverse a la derecha del PJ)
		public var moverIzda:Boolean = false;                    //true si se debe moverse a la izquierda (como si fuera la tecla de moverse a la izquierda del PJ)
        public var timerDisparo:uint = Global.cadenciaDisparo;   //cuando el timer llegue a 0, podremos volver a disparar
        public var timerSfxPaso:uint = Global.periodoSfxCaminar; //cuando el timer llegue a 0, se podrá volver a reproducir el sonido de un paso
		public var paralizado:Boolean = false;
        public var error:Boolean = false;                        //si se ha producido cualquier error desde Ogmo, valdrá true
		
        /**
         * Constructor
         * @param	x
         * @param	y
         */
		public function Enemigo(x:int, y:int,
                                _grafico:String,
                                _muerteAlContacto:String,
                                _listaNodos:Array, _velocidad:Number,
                                _copiasaltos:String,
                                _disparoDireccionalA:String,
                                _disparoDireccionalB:String,
                                _disparoDireccionalC:String,
                                _flotante:String) {
            //Control de bucles:
            var i:int;
            
			//Posicionamos la entidad:
			super(x, y);
			
			//NOTA: la gravedad y las velocidades máximas se configuran en el método update().
			
			//set hitbox & graphic:
            switch (_grafico) {
                case "bola":
                    sprite = new Spritemap(Assets.ENEM_BOLA, Global.grid, Global.grid, animEnd);
                    setHitbox(Global.grid, Global.grid);
                    //AÑADIR ANIMACIONES AQUÍ
                    break;
                case "peste":
                    sprite = new Spritemap(Assets.ENEM_PESTE, Global.grid, 2*Global.grid, animEnd);
                    setHitbox(Global.grid, 2*Global.grid);
                    //AÑADIR ANIMACIONES AQUÍ
                    break;
                case "lapa":
                    sprite = new Spritemap(Assets.ENEM_LAPA, Global.grid, Global.grid, animEnd);
                    setHitbox(Global.grid, Global.grid);
                    //AÑADIR ANIMACIONES AQUÍ
                    break;
				case "araña":
                    sprite = new Spritemap(Assets.ENEM_ARANA, Global.grid, Global.grid, animEnd);
                    setHitbox(Global.grid, Global.grid);
                    //AÑADIR ANIMACIONES AQUÍ
                    break;
				case "estalagtita":
                    sprite = new Spritemap(Assets.ENEM_ESTALAG, Global.grid, Global.grid, animEnd);
                    setHitbox(Global.grid, Global.grid);
                    //AÑADIR ANIMACIONES AQUÍ
                    break;
                case "murcielago":
                    sprite = new Spritemap(Assets.ENEM_MURCIELAGO, Global.grid, Global.grid, animEnd);
                    setHitbox(23, 9, -1, -7);
                    sprite.add("murcielago_aletear1", [0, 1, 2, 1], 0.2, true);
                    sprite.add("murcielago_aletear2", [0, 1, 2, 1, 0, 1, 2, 1, 0, 1, 2, 1, 0, 1, 2, 2, 2, 2, 2, 2, 1], 0.3, true);
                    sprite.play("murcielago_aletear1");
                    break;
                case "singrafico":
                    sprite = new Spritemap(Assets.ENEM_SPACEINVADER, Global.grid, Global.grid, animEnd);
                    setHitbox(Global.grid, Global.grid);
                    break;
                default: //ha habido un error en el grafico
                    sprite = new Spritemap(Assets.ENEM_ERROR, Global.grid, Global.grid);
                    error = true;
            }
			graphic = sprite;
            
            //Guardamos las propiedades:
            muerteAlContacto = (_muerteAlContacto == "True");
            velocidad = _velocidad;
            copiasaltos = (_copiasaltos == "True");
            flotante = (_flotante == "True");
            dDireccional = new Array(new DisparoDireccional(_disparoDireccionalA),
                                     new DisparoDireccional(_disparoDireccionalB),
                                     new DisparoDireccional(_disparoDireccionalC));
            error = dDireccional[0].error || dDireccional[1].error || dDireccional[2].error; //si se ha configurado mal desde Ogmo algún disparo, se producirá error
            
            //Configuramos los nodos a los que se dirigirá el enemigo, según lo definido desde el Ogmo Editor:
            if (_velocidad) {
                velocidad = _velocidad;
                listaNodos = _listaNodos;
                
                movimiento = new LinearMotion();
                addTween(movimiento);
                
                //nos movemos hasta el nodo inicial (la posición inicial del enemigo, en el ogmo realmente no es ningún nodo...):
                if (flotante) movimiento.setMotionSpeed(x, y, listaNodos[nodoActual].x, listaNodos[nodoActual].y, velocidad);
                nodoActual++;
            }
            
            //Configuramos el tipo:
            if (muerteAlContacto) type = "Enemigo";
            else type = "EnemigoInofensivo";
            
            //Comprobación de errores por incompatibilidad de propiedades:
		    if (copiasaltos && flotante) error = true;
		}
        
		/**
		 * update
		 */
		override public function update():void {
            //Si el pj está muerto o se está teletransportando, los enemigos se paralizan y no hacen nada:
            if (Global.pj.muerto || Global.salirPantalla_porTeletransporte) return;
            
            //Si la configuración del enemigo desde Ogmo es errónea:
            if (error) {
                graphic = new Spritemap(Assets.ENEM_ERROR, Global.grid, Global.grid);
                return;
            }
                
            //si estamos paralizados...
			if (paralizado)	{
                animar(); //colocamos la animación correspondiente
                return;   //terminamos la ejecución de este método
            }
			
			//Gestión de la gravedad en agua y aire:
            if (flotante) {
                mMaxspeed = new Point(0, 0);
                mGravity = 0;
            }
            else {
                if (collide("Agua", x, y)) {
                    mMaxspeed = new Point(velocidad, Global.maxVelEnemigos_enAgua_y);
                    mGravity = Global.gravedad_enAgua;
                }
                else {
                    mMaxspeed = new Point(velocidad, Global.maxVelEnemigos_enAire_y);
                    mGravity = Global.gravedad_enAire;
                }
            }
			
			//estamos en el suelo?
			onground = false;
			if (collide(solid, x, y + 1) || flotante)
				onground = true;
                
			//set acceleration to nothing:
			acceleration.x = 0;
            
            //Movimiento:
            if (velocidad) {
                //Si el enemigo es flotante, lo movemos como un NPC (cambiándole la posición mediante el Tween 'movimiento'):
                if (flotante) {
                    if ((x == movimiento.x) && (y == movimiento.y)) {
                        //Ordenamos al Tween LinearMotion que se ponga en movimiento:
                        movimiento.setMotionSpeed(x, y, listaNodos[nodoActual].x, listaNodos[nodoActual].y, velocidad);
                        
                        //Seleccionamos el siguiente nodo:
                        if (nodoActual >= listaNodos.length - 1) nodoActual = 0;
                        else nodoActual++;
                    }
                        
                    //Guardamos la posición actual:
                    posAnterior.x = x;
                    posAnterior.y = y;
                    //Movemos el enemigo:
                    x = movimiento.x;
                    y = movimiento.y;
                    //Evaluamos la dirección de nuestro movimiento según las posiciones anterior y actual:
                    if (posAnterior.x < x) direccionMovimiento = false;
                    else direccionMovimiento = true;
                }
                //Si el enemigo no es flotante, lo movemos como si se tratara del PJ (usando Physics.as):
                else {
                    //ordenamos movernos a la izq. o dch. según el nodo actual al que nos dirigimos, o detenernos y seleccionar el siguiente:
                    if ((listaNodos[nodoActual].x - velocidad <= x) && (x <= listaNodos[nodoActual].x + velocidad)) { //si la posición x está en un rango alrededor de la posición del nodo objetivo, detenemos al enemigo y cambiamos al siguiente nodo
                        moverDcha = false;
                        moverIzda = false;
                        //Seleccionamos el siguiente nodo:
                        if (nodoActual >= listaNodos.length - 1) nodoActual = 0;
                        else nodoActual++;
                    }
                    else if (listaNodos[nodoActual].x < x) {
                        moverDcha = false;
                        moverIzda = true;
                        direccionMovimiento = true;
                    }
                    else if (listaNodos[nodoActual].x > x) {
                        moverDcha = true;
                        moverIzda = false;
                        direccionMovimiento = false;
                    }
                    
                    //acometemos el movimiento:
                    if (moverIzda && speed.x > -mMaxspeed.x && !paralizado) {
                        acceleration.x = -movement;
                        direction = false;
                    }
                    else if (moverDcha && speed.x < mMaxspeed.x && !paralizado) {
                        acceleration.x = movement;
                        direction = true;
                    }
                }
            }
			
			//friction (apply if we're not moving, or if our speed.x is larger than maxspeed):
			if ( (!moverIzda && !moverDcha) || Math.abs(speed.x) > mMaxspeed.x )
                friction(true, false);
			
			//copiasaltos:		
			if (copiasaltos && Input.pressed("Salto")) {
				if (onground) //normal jump
                    speed.y = -jump;
			}
			
			//Disparo Direccional:
            for (var k:uint = 0; k < 3; k++) {
                if (dDireccional[k].activo) {
                    if (!dDireccional[k].timerDisparo) {
                        dDireccional[k].resetTimer();
                        
                        //Incremento de inclinación para cada proyectil (para disparos de múltiples proyectiles):
                        var DeltaTheta:Number;
                        //Desplazamiento angular inicial de inclinacioón para el primer proyectil:
                        var delta:Number;
                        
                        //Si se ha especificado un rango aleatorio para el número de proyectiles disparados...
                        var n:uint;
                        if (dDireccional[k].numProyectilesMin != dDireccional[k].numProyectilesMax)
                            n = Global.numAleat(dDireccional[k].numProyectilesMin, dDireccional[k].numProyectilesMax);
                        else
                            n = dDireccional[k].numProyectilesMin;
                        
                        //Calculamos DeltaTheta y delta:
                        if (n > 1) {
                            DeltaTheta = dDireccional[k].conoDispersion / (n-1);
                            delta = dDireccional[k].inclinacion - dDireccional[k].conoDispersion / 2;
                        }
                        else {
                            DeltaTheta = 0;
                            delta = dDireccional[k].inclinacion;
                        }
                        
                        //Añadimos los proyectiles:
                        var proyectil:Proyectil;
                        for (var i:uint = 0; i < n; i++) {
                            world.add(proyectil = new Proyectil(x + halfWidth - 4,         //posicionamos el proyectil en la centro de la entidad
                                                                y + halfHeight - 4,        //posicionamos el proyectil en el centro de la entidad
                                                                dDireccional[k].rapidez,   //el módulo del vector velocidad que tendrá el proyectil
                                                                i*DeltaTheta+delta,        //el argumento del vector velocidad
                                                                dDireccional[k].tieneMasa, //si le afecta la gravedad o no
                                                                false,                     //indicamos que es un proyectil perteneciente a un enemigo
                                                                dDireccional[k].grafico)); //especificamos el gráfico del proyectil
                        }
                    }
                    else dDireccional[k].timerDisparo--;
                }
            }
			
			//set the gravity
            gravity();
			
			//make sure we're not going too fast vertically
			//the reason we don't stop the player from moving too fast left/right is because
			//that would (partially) destroy the walljumping. Instead, we just make sure the player,
			//using the arrow keys, can't go faster than the max speed, and if we are going faster
			//than the max speed, descrease it with friction slowly.
			maxspeed(false, true);
			
			//variable jumping (tripple gravity)
			if (speed.y < 0 && !Input.check("Salto")) {
				gravity();
				gravity();
			}
			
			
			//reproducimos la animación que toque:
			animar();
			
			//set the motion. We set this later so it stops all movement if we should be stopped
            motion();
            
			//Si es colisionado por un proyectil del PJ, muere:
			if (collide("ProyectilPJ", x, y))
                world.remove(this);
		}
        
        /**
         * animar
         * gestiona las animaciones del PJ según las condiciones en que se encuentre
         */
        public function animar():void {
            //...
        }
		
        /**
         * animEnd
         * Se llamará a esta función al terminar cualquier animación:
         */
		public function animEnd():void { }
	}
}

import flash.geom.Point;
import source.Global;

/**
 * Clase disparoOrtogonal
 * Es una "miniclase" para almacenar las subpropiedades la propiedad Disparo Ortogonal
 */
class DisparoDireccional {
    //subpropiedades:
    public var activo:Boolean = false;        //indica si esta propiedad está activa
    public var numProyectilesMin:uint = 0;    //número de proyectiles disparados como mínimo
    public var numProyectilesMax:uint = 0;    //número de proyectiles disparados como máximo
    public var inclinacion:uint = 0;          //inclinación, en grados, del disparo
    public var conoDispersion:uint = 0;       //cono de dispersión para el disparo de múltiples proyectiles, en grados
    public var periodo:uint = 0;              //periodo de disparo, medido en frames
    public var rapidez:uint = 0;              //módulo de la velocidad de los proyectiles, medidos en pixeles/frame
    public var tieneMasa:Boolean = false;     //true si el proyectil es afectado por la gravedad
    public var grafico:String = "singrafico"; //el gráfico del proyectil
    
    //otras variables:
    public var timerDisparo:uint = 0;
    public var error:Boolean = false; //si vale true, se ha producido un error desde Ogmo
    
    public function DisparoDireccional(_disparoDireccional:String) {
        var _array:Array = _disparoDireccional.split(','); //dividimos la cadena mediante el separador ','
        
        if (_array.length == 8) { //este if protege de errores desde Ogmo
            activo = (_array[0] == "1");
            inclinacion = uint(_array[2]);
            conoDispersion = uint(_array[3]);
            periodo = uint(_array[4]);
            rapidez = uint(_array[5]);
            tieneMasa = (_array[6] == "1");
            grafico = String(_array[7]);
            
            //El número de proyectiles los leemos aparte, porque pueden expresar números aleatorios:
			if (_array[1].search("-") > 0) { //si en el ogmo se ha establecido un rango de números aleatorios...
                _array = _array[1].split('-'); //dividimos la cadena mediante el separador '-', nos dará el mínimo y el máximo
                if (_array.length == 2) { //este if protege de errores desde Ogmo
                    numProyectilesMin = uint(_array[0]);
                    numProyectilesMax = uint(_array[1]);
                }
                else
                    error = true;
            }
            else //si en el ogmo se ha establecido un rango de números aleatorios, el mínimo coincide con el máximo
                numProyectilesMin = numProyectilesMax = uint(_array[1]);
        }
        else
            error = true;
        
        resetTimer();
    }
    
    public function resetTimer():void {        
        timerDisparo = periodo;
    }
}












//